/** \file    Transform2.cpp
  * \brief   Builds affine (general case) approximation of segments motion,
  *	  unlike Transform.cpp functions here do not depend on GSL and have performance enhancements.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/segm/src/Transform2.cpp,v 1.3 2007/08/26 13:43:26 cscom1r4 Exp $
  */

#include <glib/g2/p2p_matcher.h>
#include <glib/g2/translation.h>
#include <glib/g2/rigid.h>
#include <glib/g2/rigid_scale.h>
#include <glib/g2/affine.h>

#include "segm/Segmentation.h"
#include "imglib/type.h"
#include "typelib/affine.h"

std::ostream & operator << (std::ostream & os, const affine & a); //defined in imglib

using std::clog;
using std::endl;

template <class T>
void restoreTransform2(affine & a, const Segmentation & segm)
{
  clog << "Matching point sets with " << T::name() << " motion...\n";

  g2::p2p_matcher<T> m;
	unsigned i;
	for (i = 0; i < segm.count(); i++)
		m.match(
			segm.segmentByIndex(i).centre,
			segm.segmentByIndex(i).centre + double_point(segm.segmentByIndex(i).adisplacement()));

  T t;
  m.get_transform(t);
  g2::affinef a0 = t;
  a.x = a0.d.x;
  a.y = a0.d.y;
  a.xx = a0.r.xx;
  a.xy = a0.r.xy;
  a.yx = a0.r.yx;
  a.yy = a0.r.yy;

	clog << a << endl;
}

void Segmentation::determineTransform2(affine & a, TransformClass transformClass) const
{
	switch (transformClass) {
	case TRANSFORM_AFFINE: {
    restoreTransform2<g2::affinef>(a, *this);
		break;
	}
	case TRANSFORM_TRANSLATION: {
    restoreTransform2<g2::translationf>(a, *this);
		break;
	}
	case TRANSFORM_RIGID: {
    restoreTransform2<g2::rigidf>(a, *this);
		break;
	}
	case TRANSFORM_RIGID_ZOOM: {
    restoreTransform2<g2::rigid_scalef>(a, *this);
		break;
	}
	default:
		assert(false);
	}
}

template <>
void Segmentation::determineTransform(affine & t, TransformClass transformClass) const
{
	determineTransform2(t, transformClass);
}

template <class T>
void applyTransform(Segmentation & s, void (Segment::*op)(int_point), const T & t)
{
	s.positions();
	int n = s.count();
	int i;
	for (i = 0; i < n; i++) {
		Segment & g = s.segmentByIndex(i);
		point<double> moved = t(g.centre);
		(g.*op)( int_point(
			round(moved.x - g.centre.x),
			round(moved.y - g.centre.y) 
		) );
	}
}

template <class T>
void Segmentation::displaceByTransform(const T & t) 
{
	applyTransform(*this, &Segment::setAdisplacement, t);
}

template void Segmentation::displaceByTransform(const img::QuadraticForm &);
template void Segmentation::displaceByTransform(const affine &);


template <class T>
void Segmentation::predictByTransform(const T & t) 
{
	applyTransform(*this, &Segment::setPdisplacement, t);
}

template void Segmentation::predictByTransform(const img::QuadraticForm &);
template void Segmentation::predictByTransform(const affine &);
